﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DemoTest.Bll.Handlers;
using DemoTest.Bll.Models;
using Nido.Common.BackEnd;
using Nido.Common.Web;
using System.Data.Entity;
using Nido.Common;
using System.Text;
using Nido.Common.FrontEnd;
using System.Linq.Expressions;
using Nido.Common.Utilities.Alerting.Sms;
using Nido.Common.Utilities.Alerting.Email;
using EntityFramework.Extensions;
using RefactorThis.GraphDiff;
using Nido.Common.Utilities.Cache;

namespace DemoTestApplication.UserControls
{
    public partial class ucStudentList : BaseUserControl<IEnumerable<Student>>
    {
        public const int PAGE_SIZE = 10;

        public enum ControlModes
        {
            NavDisabled,
            NavEnabled,
            NextDisabled,
            PreviousDisabled
        }

        public int CurrentPage
        {
            get
            {
                return ViewStateHelper.GetValue<int>(this.ViewState, "CurrentPage", 0);
            }
            set
            {
                ViewStateHelper.SetValue(this.ViewState, "CurrentPage", value);
            }
        }

        private int _TotalItemCount;
        public int TotalItemCount
        {
            get
            {
                return _TotalItemCount;
            }
            set
            {
                _TotalItemCount = value;
                if (value < PAGE_SIZE)
                    this.ResetUserInterface(ControlModes.NavDisabled);
                else if (CurrentPage == 0)
                    this.ResetUserInterface(ControlModes.PreviousDisabled);
                else if (CurrentPage * PAGE_SIZE + PAGE_SIZE > TotalItemCount)
                    this.ResetUserInterface(ControlModes.NextDisabled);
                else
                    this.ResetUserInterface(ControlModes.NavEnabled);
            }
        }

        public string PageNumberPanel
        {
            get;
            set;
        }

        public override IEnumerable<Student> BindedObject
        {
            get;
            set;
        }

        private StudentHandler handlerStudent = new StudentHandler();
        protected void Page_Load(object sender, EventArgs e)
        {
            handlerStudent.GetFirstGeneric(x => (x.Age == 10 && x.CanDelete == true));
            LoadData();
            handlerStudent.StudentBulkInsert(null);
        }

        protected override void LoadData()
        {
            SetPageNumberPanel();
            // NOTE:
            // I am using another method here to count the total number of record in the DB without loading them.
            // The cache function need to be updated and should implement differently. 
            // I think I should load the whole recod set and cache.
            
            GenericResponse<IEnumerable<Student>> response = handlerStudent
                .Include("StudentCourses.Course").Include("HomeAddress")
                .Include("OfficeAddress").FromCache()
                .GetAllGenericFromCache(x => x.IsActive == true, new NidoCachePolicy(120), null);

            if (response.Successful)
            {
                this.PageNmbers.Text = PageNumberPanel;
                BindedObject = response.Result.OrderBy(x => x.Age).Skip(CurrentPage * PAGE_SIZE)
                    .Take(PAGE_SIZE);
                this.GridView1.DataSource = BindedObject;
                this.GridView1.DataBind();
            }
            else
                this.DisplayError(response);

            this.StudentCombo1.DataBind();
        }

        protected override void ResetData()
        {
            CurrentPage = 0;
            LoadData();
        }

        public override void UpdateUI(Nido.Common.FrontEnd.ControlModes ControlMode)
        {
            throw new NotImplementedException();
        }

        protected void lnkbtnPrevious_Click(object sender, EventArgs e)
        {
            CurrentPage -= 1;
            LoadData();
        }

        protected void lnkbtnNext_Click(object sender, EventArgs e)
        {
            CurrentPage += 1;
            LoadData();
        }

        protected void ButtonRefresh_Click(object sender, EventArgs e)
        {
            ResetData();
        }

        protected void ButtonSearch_Click(object sender, EventArgs e)
        {
            SetPageNumberPanel(x => x.Age > 10 && x.StudentId < 300 && x.StudentCourses.Count() > 1);

            GenericResponse<IEnumerable<Student>> response = handlerStudent
                .Include("StudentCourses.Course").GetAllGeneric(x => x.Age > 10 && x.StudentId < 300 && x.StudentCourses.Count() > 1);

            if (response.Successful)
            {
                this.PageNmbers.Text = PageNumberPanel;
                BindedObject = response.Result.OrderBy(x => x.Age).Skip(CurrentPage * PAGE_SIZE)
                    .Take(PAGE_SIZE);
                this.GridView1.DataSource = BindedObject;
                this.GridView1.DataBind();
            }
            else
                this.DisplayError(response);
        }

        protected void ButtonUpdate_Click(object sender, EventArgs e)
        {
            StudentHandler handlerStudent = new StudentHandler();
            GenericResponse<Student> stdRes = handlerStudent.GetFirstGeneric(x => x.StudentId < 34);
            if (stdRes.Successful)
            {
                stdRes.Result.Age = 1000;
                GenericResponse<Student> stdUpRes = handlerStudent.UpdateGeneric(stdRes.Result);
            }
            //UpdateRecord(BindedObject.FirstOrDefault(x => x.StudentId < 34));
        }

        protected void ButtonSingle_Click(object sender, EventArgs e)
        {
            SelectSingle(1);
        }

        protected void ButtonSms_Click(object sender, EventArgs e)
        {
            // Please do not over use this facility as 
            // this cost about 1 rupees for every message you send
            /*MAlertSSmsClient smsClient = new MAlertSSmsClient();
            if (smsClient.Send(smsClient.Create("this is a test", "94773887502", 3, 2)))
                this.DisplayError(new GenericResponse(true, "message sent"));
            else
                this.DisplayError(new GenericResponse(false, "message sent failed"));*/
        }

        protected void ButtonEmail_Click(object sender, EventArgs e)
        {
            /*MAlertSNetEmailClient emailClient = new MAlertSNetEmailClient();
            if (emailClient.Send(emailClient.Create("neeroholan@yahoo.com"
                , "Nirosh", "Hello this is a test message"
                , "Dear Nirosh, this is a test"
                , "")))
                this.DisplayError(new GenericResponse(true
                    , "email sent"));
            else
                this.DisplayError(new GenericResponse(false
                    , "email failed to sent"));*/
        }

        protected void ButtonUpdate2_Click(object sender, EventArgs e)
        {
            GenericResponse<IEnumerable<Student>> res = handlerStudent.Include("StudentCourses.Course").GetAllGeneric(x => x.StudentId < 34);
            UpdateRecord2(res.Result.First());
        }

        private void SetPageNumberPanel()
        {
            TotalItemCount = handlerStudent.CountGeneric();
            StringBuilder sb = new StringBuilder();
            if (CurrentPage == 0)
                PageNumberPanel = sb.Append("1, 2, 3, ..., ").Append(TotalItemCount / PAGE_SIZE).ToString();
            else
                PageNumberPanel = sb.Append("1, ..., ").Append(CurrentPage + 1).Append(", ").Append(CurrentPage + 2)
                    .Append(", ").Append(CurrentPage + 3).Append(", ..., ").Append(TotalItemCount / PAGE_SIZE).ToString();
        }

        private void SetPageNumberPanel(Expression<Func<Student, bool>> searchExpression)
        {
            int totalCount = handlerStudent.CountGeneric(searchExpression);
            StringBuilder sb = new StringBuilder();
            if (totalCount < PAGE_SIZE)
                PageNumberPanel = sb.Append("1...").ToString();
            else if (CurrentPage == 0)
                PageNumberPanel = sb.Append("1, 2, 3, ..., ").Append(totalCount / PAGE_SIZE).ToString();
            else
                PageNumberPanel = sb.Append("1, ..., ").Append(CurrentPage + 1).Append(", ").Append(CurrentPage + 2)
                    .Append(", ").Append(CurrentPage + 3).Append(", ..., ").Append(totalCount / PAGE_SIZE).ToString();
        }

        private void ResetUserInterface(ControlModes controlMode)
        {
            switch (controlMode)
            {
                case ControlModes.NavDisabled: { this.ButtonPrevious.Enabled = false; this.ButtonNext.Enabled = false; } break;
                case ControlModes.NavEnabled: { this.ButtonNext.Enabled = true; this.ButtonPrevious.Enabled = true; } break;
                case ControlModes.NextDisabled: { this.ButtonNext.Enabled = false; this.ButtonPrevious.Enabled = true; } break;
                case ControlModes.PreviousDisabled: { this.ButtonPrevious.Enabled = false; this.ButtonNext.Enabled = true; } break;
            }
        }

        private void UpdateRecord(Student student)
        {
            student.Age = 1;
            student.Description = "Editted on " + DateTime.Now;
            student.Name = "Nirosh ";

            Course course = new Course();
            course.EndDate = DateTime.Now;
            course.IsActive = false;
            course.IsWeekEnd = true;
            course.Name = "Newly added course on " + DateTime.Now;
            course.Period = 10;
            course.StartDate = DateTime.Now;

            StudentCourse stdCourse = new StudentCourse();
            stdCourse.StudentId = student.StudentId;
            stdCourse.CourseId = course.CourseId;
            stdCourse.Course = course;

            student.StudentCourses.Add(stdCourse);

            student.EncryptRecords<Student>();

            GenericResponse<Student> response = handlerStudent.UpdateGeneric(student);

            //
            //student.Age = 120;
            //student.Description = "Editted on " + DateTime.Now;
            //GenericResponse<Student> response = handlerStudent.UpdateGeneric(student, student.StudentId);

            this.DisplayError(response);
        }

        private void UpdateRecord2(Student student)
        {
            student.DecryptRecords<Student>();
            student.Age = 308;
            student.Description = "Editted on " + DateTime.Now;
            student.Name = string.Empty;

            student.StudentCourses.FirstOrDefault().Course.Period = 308;
            student.StudentCourses.FirstOrDefault().Course.Name = "Eddited on " + DateTime.Now;

            // Remove will delete all the records including the onces that are not loaded this time
            // Remove a set of given elements will only delete them
            student.StudentCourses.Remove(student.StudentCourses.FirstOrDefault(x=>x.StudentCourseId == 10));

            Course course = new Course();
            course.EndDate = DateTime.Now;
            course.IsActive = false;
            course.IsWeekEnd = true;
            course.Name = "Newly added course on " + DateTime.Now;
            course.Period = 10;
            course.StartDate = DateTime.Now;

            StudentCourse stdCourse = new StudentCourse();
            stdCourse.StudentId = student.StudentId;
            stdCourse.CourseId = course.CourseId;
            stdCourse.Course = course;

            student.StudentCourses.Add(stdCourse);

            StudentHandler stdentHandler = new StudentHandler();

            student.EncryptRecords<Student>();

            GenericResponse<Student> response = stdentHandler
                .UpdateGraphGeneric(student
                , map => map.OwnedCollection(p => p.StudentCourses
                    , with => with.OwnedEntity(p => p.Course)));

            // When the object is not attached errors comes then go with this option
            // student.Age = 120;
            // student.Description = "Editted on " + DateTime.Now;
            // GenericResponse<Student> response = handlerStudent.AttachChild(course).AttachChild(stdCourse).UpdateGeneric(student);

            // Want to update only the paramerters that were newly updated and you just want other properties untouched
            // Then go with this option, Once you pass the primary key the system think that you want it to find the
            // record from the DB and do only the update.
            // GenericResponse<Student> response = handlerStudent.UpdateGeneric(student, student.StudentId);

            this.DisplayError(response);
        }

        private void SelectSingle(int p)
        {
            GenericResponse<Student> response = handlerStudent.Include(x => x.StudentCourses)
                .GetSingleGeneric(x => x.StudentId == p);
            // Demo code only
            if (response.Successful)
                this.DisplayError(response);
            else
                this.DisplayError(response);
        }

        protected void ButtonUpdate3_Click(object sender, EventArgs e)
        {
            GenericResponse<Student> stdResponse = handlerStudent.Include(x=>x.StudentCourses).GetFirstGeneric(x => x.StudentId == 22);
            if (stdResponse.Successful)
            {
                stdResponse.Result.Address = "Test" + new Random().Next();
                handlerStudent.UpdateGeneric(t => t.StudentId > 0, t2 => new Student { Name = "Updated" });
            }
        }

        protected void ButtonSession_Click(object sender, EventArgs e)
        {
            // Demo code only
            SessionHelper.SetValue("TestId", 12);
            int id = SessionHelper.GetValue<int>("TestId");

            CookieHelper.Set("Main", "TestId", "13");
            string idStr = CookieHelper.Get("Main", "TestId");

            ViewStateHelper.SetValue(this.ViewState, "TestId", 12);
            id = ViewStateHelper.GetValue<int>(this.ViewState, "TestId");
        }

        protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            if (e.CommandName == "Delete")
            {
                int id = Convert.ToInt32(e.CommandArgument);
                //handlerStudent.Delete(id);
                GenericResponse<Student> response = handlerStudent.DeleteGeneric(x => x.StudentId == id);
                this.DisplayError(response);
            }
        }

        protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
        {

        }

        protected void GridView1_RowDeleted(object sender, GridViewDeletedEventArgs e)
        {
            LoadData();
        }
    }
}